#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h> // For atoi function

#include "can_rx.h"
#include "mosquitto.h"
#include "cJSON.h" // cJSON library for JSON parsing
#include "linux/can.h"

typedef struct s_conn_para {
    char *hostname;
    char *pub_topic;
    char *clientId;
    char *username;
    char *password;
    int port;
    char payload[256];
    char *sub_topic;
    int  keepalive;
    int  qos;
} conn_para_t;

void mqtt_clean(struct mosquitto *mosq);
static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg);

int main(int argc, char **argv)
{
    struct mosquitto *mosq;
    int mid, mid1;
    int retain = 0;
    int session = true;
    struct can_frame received_frame;
    const char *interface_name = "can0";

    conn_para_t conn_para = {
        "iot-06z00i9k03hcz6s.mqtt.iothub.aliyuncs.com",
        "/sys/h098jXhNP9d/mqtt/thing/event/property/post",
        "h098jXhNP9d.mqtt|securemode=2,signmethod=hmacsha256,timestamp=1720751526199|",
        "mqtt&h098jXhNP9d",
        "16aae5231f7378909fd972fa0212ad774e5e75eb19532d32ccca175232aa7143",
        1883,
        "",
        "/sys/h098jXhNP9d/mqtt/thing/event/property/post_reply",
        60,
        0
    };

    mosquitto_lib_init();

    mosq = mosquitto_new(conn_para.clientId, session, NULL);

    if (mosquitto_username_pw_set(mosq, conn_para.username, conn_para.password) != MOSQ_ERR_SUCCESS) {
        printf("connect server failure:%s\n", strerror(errno));
        goto cleanup;
    }

    printf("mqtt connect parameters set OK\n");

    if (mosquitto_connect(mosq, conn_para.hostname, conn_para.port, conn_para.keepalive) != MOSQ_ERR_SUCCESS) {
        printf("connect server failure:  %s\n", strerror(errno));
        goto cleanup;
    }
    printf("connect ok\n");
	mosquitto_message_callback_set(mosq, my_message_callback);
    if (mosquitto_loop_start(mosq) != MOSQ_ERR_SUCCESS) {
        printf("mosquitto_loop_start_failure: %s\n", strerror(errno));
        goto cleanup;
    }

    // Subscribe to MQTT topic
    if (mosquitto_subscribe(mosq, &mid, conn_para.sub_topic, conn_para.qos) != MOSQ_ERR_SUCCESS) {
        printf("mosquitto subscribe failure: %s\n", strerror(errno));
        goto cleanup;
    }
    printf("subscribe OK\n");

    while (1) {
        received_frame = receive_can_message(interface_name);
       snprintf(conn_para.payload, sizeof(conn_para.payload),"{\"method\":\"thing.service.property.set\",\"id\":\"10353468\",\"params\":{\"can_id\":%d,\"can_DLC\":%d,\"can_data\":%d},\"version\":\"1.0.0\"}",
                 (int)received_frame.can_id, (int)received_frame.can_dlc, (int)received_frame.data[1]);

        if (mosquitto_publish(mosq, &mid1, conn_para.pub_topic, strlen(conn_para.payload), conn_para.payload, conn_para.qos, retain) != MOSQ_ERR_SUCCESS) {
            printf("mosquitto publish data failure: %s\n", strerror(errno));
            continue;
        }
        printf("published message: %s\n", conn_para.payload);
        sleep(3);

    }

cleanup:
    mqtt_clean(mosq);
    return 0;
}

void mqtt_clean(struct mosquitto *mosq)
{
    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();
}

static void my_message_callback(struct mosquitto *mosq, void *obj, const struct mosquitto_message *msg)
{
    printf("received message: %s\n", (char *)msg->payload);

    // Parse JSON message using cJSON library
    cJSON *root = cJSON_Parse((char *)msg->payload);
    if (root == NULL) {
        printf("JSON parsing error\n");
        return;
    }

    // Example: Handle message based on the method field
    cJSON *method = cJSON_GetObjectItem(root, "method");
    if (method != NULL && cJSON_IsString(method)) {
        if (strcmp(method->valuestring, "thing.service.property.set") == 0) {
            // Example: Handle thing.service.property.set message
            cJSON *params = cJSON_GetObjectItem(root, "params");
            if (params != NULL) {
                cJSON *can_id = cJSON_GetObjectItem(params, "can_id");
                cJSON *can_dlc = cJSON_GetObjectItem(params, "can_DLC");
                cJSON *can_data = cJSON_GetObjectItem(params, "can_data");

                if (cJSON_IsNumber(can_id) && cJSON_IsNumber(can_dlc) && cJSON_IsNumber(can_data)) {
                    int id = can_id->valueint;
                    int dlc = can_dlc->valueint;
                    int data = can_data->valueint;

                    printf("Received CAN message: id=%d, dlc=%d, data=%d\n", id, dlc, data);

                    // Add your logic to process received CAN message here
                    // Example: You can update device state, send response, etc.
                } else {
                    printf("Invalid or missing CAN data fields\n");
                }
            } else {
                printf("Missing params object in message\n");
            }
        } else {
            printf("Unsupported method: %s\n", method->valuestring);
        }
    } else {
        printf("Missing or invalid method field\n");
    }

    cJSON_Delete(root);
}
